#include <stdio.h>
#include <stdlib.h>
#include <fstream> 
#include <iostream>
#include <opencv2/opencv.hpp>
#include <unistd.h>
#include <chrono>
#include "antiShape.hpp"
#include "capturer.hpp"
#include "sender.hpp"



void pullFlowPro(std::string camIp, std::string camUser, std::string camPasswd, 
                 std::string videoPath, AntiShape& antiShapeObj, std::queue<cv::Mat>& qData){
    // if videoPath != None:
    //     camCap = VideoCap(videoPath)
    // else:
    //     camCap = CameraCap(camIp, camUser, camPasswd)

    CameraCap camCap(camUser,camPasswd,camIp);

    struct timeval startTime, stopTime;
    long elapsed;
    gettimeofday(&startTime, NULL);

    cv::Mat frame;
    int count = 0;
    while(1){
        bool ret = camCap.getOneFrame(frame);
        if(!ret){
            break;
        }
        
        // cv::resize(frame, frame, cv::Size(1280,720));
        cv::resize(frame, frame, cv::Size(640,360));


        // if(qData.size() < 10){
        //     qData.push(frame);
        // }
        antiShapeObj.put(frame);

        count = (count + 1)%30;
        if(count == 0){
            gettimeofday(&stopTime, NULL);
            elapsed = (stopTime.tv_sec-startTime.tv_sec) * 1000000 + (stopTime.tv_usec - startTime.tv_usec);
            // std::cout << "pull fps: " << 30.0 * 1000000.0 / elapsed << std::endl;
            gettimeofday(&startTime, NULL);
        }
    }
}

void dealPro(AntiShape& antiShapeObj, std::queue<cv::Mat>& qData){

    struct timeval startTime, stopTime, startTime1, stopTime1;
    long elapsed;
    gettimeofday(&startTime, NULL);

    
    int count = 0;
    while(1){
        // gettimeofday(&startTime1, NULL);
        cv::Mat frameAffined, frame;
        antiShapeObj.get(frameAffined, frame);
        if(!frameAffined.empty()){
            // gettimeofday(&stopTime1, NULL);
            // elapsed = (stopTime1.tv_sec-startTime1.tv_sec) * 1000000 + (stopTime1.tv_usec - startTime1.tv_usec);
            // std::cout << "deal time: " << elapsed / 1000.0 << std::endl;

            count = (count + 1) % 30;
            cv::Mat temp;
            cv::vconcat(frame, frameAffined, temp);
            if(qData.size() < 10){
                // qData.push(temp);
                qData.push(frameAffined);
            }
            if(count == 0){
                gettimeofday(&stopTime, NULL);
                elapsed = (stopTime.tv_sec-startTime.tv_sec) * 1000000 + (stopTime.tv_usec - startTime.tv_usec);
                // std::cout << "deal fps: " << 30.0 * 1000000.0 / elapsed << std::endl;
                gettimeofday(&startTime, NULL);
            }
        }
            
        sleep(0.01);
    }

}


void pushPro(StreamPusher& senderObj,
             std::queue<cv::Mat>& qData){
    cv::Mat temp;
    auto start = std::chrono::high_resolution_clock::now();
    int count = 0;
    while(1){
        if(qData.size() > 0){
                  count++;

            cv::Mat image = qData.front();
            qData.pop();
            auto end = std::chrono::high_resolution_clock::now();
            std::chrono::duration<double> elapsed = end - start;

        // 如果经过的时间超过1秒，输出计数并重置计时器
            if (elapsed.count() >= 1.0) {
                std::cout << "Count: " << count << std::endl;

            // 重置计数器和计时器
                count = 0;
                start = std::chrono::high_resolution_clock::now();
            }
            cv::cvtColor(image, temp, cv::COLOR_BGR2YUV_IYUV);
            senderObj.push(image);
        }
        sleep(0.01);
    }
}

int main(void){
    std::string camIp = "192.168.6.135";
    std::string camUser = "admin";
    std::string camPasswd = "hxzh2019";
    std::string desIp = "192.168.6.144";
    std::string port = "31935";
    std::string subStr = "/http_flv/test1314";

    std::queue<cv::Mat> qData;
    AntiShape antiShape("../config/config.json");
    StreamPusher sender(desIp,port,subStr);

    std::thread thread0(pullFlowPro, camIp, camUser, camPasswd, "", std::ref(antiShape), std::ref(qData));
    std::thread thread1(dealPro, std::ref(antiShape), std::ref(qData));
    std::thread thread2(pushPro, std::ref(sender), std::ref(qData));

    thread0.join();
    thread1.join();
    thread2.join();

    std::cout << "hello world" << std::endl;

    return 0;
}
